#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::analyse() {
	programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::programme() {
// <programme> ::= debut <seqInst> fin <EOF>

	sauterSymCour("debut");
	seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::seqInst() {
// <seqIns> ::= <inst> ; { <inst> ; }

	do {
		inst();
		sauterSymCour(";");
	} while (ls.getSymCour()=="<VARIABLE>" ||
                 ls.getSymCour()=="si" ||
                 ls.getSymCour()=="tantque" ||
                 ls.getSymCour()=="repeter" ||
                 ls.getSymCour()=="lire" ||
                 ls.getSymCour()=="ecrire" ||
                 ls.getSymCour()=="pour"
                );
	// tant que le symbole courant est un debut possible d'instruction...
}

////////////////////////////////////////////////////////////////////////////////
   void LecteurPhraseAvecTable::inst() {           // <inst>       ::= <affectation> | <instSi> | <instTq> | <instRepeter> | <instLire> | <instEcrire>
	if (ls.getSymCour()==("<VARIABLE>"))
            affectation();                              // appel à la méthode affectation()
        else if (ls.getSymCour()==("si"))
            instSi();
        else if (ls.getSymCour()==("tantque"))
            instTq();
        else if (ls.getSymCour()==("repeter"))
            instRepeter();
        else if (ls.getSymCour()==("lire"))             
            instLire();                                 // appel à la méthode instLire permettant de lire une variable (type <VARIABLE>) au clavier
        else if (ls.getSymCour()==("ecrire"))           
            instEcrire();                               // appel à la méthode instEcrire, permettant l'affichage à l'ecran de variables, entiers, chaines.
        else if (ls.getSymCour()==("pour"))           
            instPour(); 
        else
		erreur("<inst>");
   }
   
//----------------------------- Instructions SI --------------------------------
   
  void LecteurPhraseAvecTable::instSi() {          // <instSi>     ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> } [ sinon <seqInst> ] finsi
      
        sauterSymCour("si");
        sauterSymCour("(");
        expBoolOU();
        sauterSymCour(")");

        seqInst();
               
       while (ls.getSymCour()==("sinonsi")) {
          sauterSymCour("sinonsi");
          sauterSymCour("(");
          expBoolOU();
          sauterSymCour(")");
          seqInst();
        }
                
        if (ls.getSymCour()=="sinon") {
           sauterSymCour("sinon");
           seqInst();   
        }
        sauterSymCour("finsi");
  }
  
//----------------------------- Instructions TQ --------------------------------

  void LecteurPhraseAvecTable::instTq() {          // <instTq>     ::= tantque ( <expBool> ) <seqInst> fintantque
      
       sauterSymCour("tantque");
       sauterSymCour("(");
       expBoolOU();
       sauterSymCour(")");
       seqInst();
       sauterSymCour("fintantque");
      
  }
  
//------------------------- Instructions Repeter -------------------------------

  void LecteurPhraseAvecTable::instRepeter() {     // <instRepeter>::= repeter <seqInst> jusqua ( <expBool> )
       sauterSymCour("repeter");
       seqInst();
       sauterSymCour("jusqua");
       sauterSymCour("(");
       expBoolOU();
       sauterSymCour(")");
       
  }
  
//------------------------- Instructions Lire ----------------------------------
  
  void LecteurPhraseAvecTable::instLire()  {      // <instLire>   ::= lire ( <variable>) 
       sauterSymCour("lire");
       sauterSymCour("(");
       if (ls.getSymCour()=="<VARIABLE>") {
                facteur();
                sauterSymCour(")");
        }
        else
                erreur("<variable>");
   } 
  
//----------------------- Instructions Ecrire ----------------------------------
  
  void LecteurPhraseAvecTable::instEcrire(){      // <instEcrire> ::= ecrire ( <chaine> | <expression> )  
       
        sauterSymCour("ecrire");
        sauterSymCour("(");
        
        if (ls.getSymCour()=="<CHAINE>") {
                testerSymCour("<CHAINE>");
                ts.chercheAjoute(ls.getSymCour());
                ls.suivant();
        }
        else
                expression();
        
        sauterSymCour(")");
    
   }
//----------------------- Instructions Pour ------------------------------------
  
  void LecteurPhraseAvecTable::instPour(){         // <instPour>   ::= pour ( affectation ; <expBoolOU>; affectation ) <seqInst> finpour 
      
      sauterSymCour("pour");
      sauterSymCour("(");
      
      affectation();
      sauterSymCour(";");
      
      expBoolOU();
      
      sauterSymCour(";");
      affectation();
      sauterSymCour(")");
      
      seqInst();
      sauterSymCour("finpour");     

  } 
   
   
   
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::affectation() {
// <affectation> ::= <variable> = <expression>

	//sauterSymCour("<VARIABLE>");
	testerSymCour("<VARIABLE>");
	ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour("=");
	expression();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expression() {     // <expression> ::= <terme> {<opAdd><terme>}

	terme();                                // appel de la méthode terme pour tester si le premier élément en est un
	while ( ls.getSymCour()=="+" ||         // tant que le symbole lu est un '+'
                ls.getSymCour()=="-" ) {        // ou un '-'
		opAdd();                        // on appelle la méthode opAdd() pour continuer l'analyse
		terme();                        // on appelle la méthode terme()
	}
   }

////////////////////////////////////////////////////////////////////////////////

   void LecteurPhraseAvecTable::terme() {          // <terme> ::= <facteur> {<opMult><facteur>}

	facteur();                              // appel de la méthode facteur pour savoir si le premier élément en est un 
	while ( ls.getSymCour()=="*" ||         // tant que le symbole lu est un '*'
                ls.getSymCour()=="/" ) {        // ou un '/'
		opMult();                       // on appelle la méthode opMult() pour continuer l'analyse
		facteur();                      // on appelle la méthode facteur()
	}
   }


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::facteur() {
// <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )
//               <entier>  |  <variable>  |  <opUnaire>  <expBoolOU>  |  ( <expBoolOU> )
	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>") {
		ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	} 
        /*else if (ls.getSymCour()=="-") {
		ls.suivant();
		facteur();
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		expression();
		sauterSymCour(")");
	} else
		erreur("<facteur>");*/
        
        else if (ls.getSymCour()=="-" || ls.getSymCour()=="non") {
		opUnaire();
		expBoolOU();
               
                
	} else if (ls.getSymCour()=="(") {
                sauterSymCour("(");
		expBoolOU();
		sauterSymCour(")");
                
	} else
		erreur("<facteur>");
   
}
////////////////////////////////////////////////////////////////////////////////

//-------------------------- Expressions booléennes ET -------------------------

   void LecteurPhraseAvecTable::expBoolET() {      // <expBoolET>    ::= <relation> { <opBoolET> <relation> }
        relation();
        while ( ls.getSymCour()=="et") {        // si symbole courant est 'et'
		opBoolET();                     // appel de la méthode opBoolET() pour continuer l'analyse
		relation();                     // appel de la méthode relation pour tester l'élément suivant
        }
   }    
   
   
//-------------------------- Expressions booléennes OU -------------------------

   void LecteurPhraseAvecTable::expBoolOU() {      // <expBoolOU>    ::= <expBoolET> { <opBoolOU> <expBoolET> }
        expBoolET();
        while ( ls.getSymCour()=="ou") {        // si symbole courant est 'ou'
		opBoolOU();                     // appel de la méthode opBoolOU() pour continuer l'analyse
		expBoolET();                    // appel de la méthode expBoolET
        }
   }    
   
//---------------------------------- [ ou ] ------------------------------------

   void LecteurPhraseAvecTable::opBoolOU() {         // <opBool> ::= ou

        if      (ls.getSymCour()=="ou" )         // si le symbole courant est un 'ou'
                        ls.suivant();            // on passe au suivant
        else                                    // sinon
		erreur("<opBoolOU>");             // on appelle la methode erreur avec le message "<opBool>"
}
   
//------------------------------- [ et ] ---------------------------------------

   void LecteurPhraseAvecTable::opBoolET() {         // <opBool> ::= et

        if (    ls.getSymCour()=="et" )         // si le symbole courant est un 'et'
		ls.suivant();                   // on passe au suivant
        else                                    // sinon
		erreur("<opBoolET>");           // on appelle la methode erreur avec le message "<opBool>"
 }  
   
////////////////////////////////////////////////////////////////////////////////
   
//-------------------------------- Relation ------------------------------------

   void LecteurPhraseAvecTable::relation() {       // <relation> ::=
                                                // <expression> {<opRel> <expression>}

        expression();                           // appel de la méthode expression pour vérifier la syntaxe
        
        while ( ls.getSymCour()=="==" ||        // tant que le symbole lu est un '=='
                ls.getSymCour()=="!=" ||        // ou '!='
                ls.getSymCour()=="<=" ||        // ou '<'
                ls.getSymCour()=="<"  ||        // ou '<='
                ls.getSymCour()==">=" ||        // ou '>'
                ls.getSymCour()==">") {         // ou '>='
        opRel();                                // appel de la méthode opRel() pour continuer l'analyse
        expression();                           // appel de la méthode expression pour vérifier la syntaxe
        }
   }

//---------------------- [ == | != | < | <= | > | >= ] -------------------------

   void LecteurPhraseAvecTable::opRel() { // <opRel> ::= == | != | < | <= | > | >=
       
        if (    ls.getSymCour()=="==" ||
                ls.getSymCour()=="!=" ||
                ls.getSymCour()=="<=" ||
                ls.getSymCour()=="<"  ||
                ls.getSymCour()==">=" ||
                ls.getSymCour()==">"  )
                ls.suivant();
        else
                erreur("<opRel>");
   }

//------------------------------ [ - | non ] -----------------------------------

   void LecteurPhraseAvecTable::opUnaire(){ // <opUnaire> ::= - | non
       
        if (    ls.getSymCour()=="-" ||
                ls.getSymCour()=="non")
                ls.suivant();
        else
                erreur("<opUnaire>");
   }
  
//-------------------------------- [ + | - ] -----------------------------------

   void LecteurPhraseAvecTable::opAdd() {          // <opAdd> ::= + | -

	if (    ls.getSymCour()=="+" ||         // si le symbole lu est un '+'
                ls.getSymCour()=="-" )          // ou '-'
		ls.suivant();                   // on passe au suivant
	else                                    // sinon
		erreur("<opAdd>");              // on affiche une erreur avec détails
   }

//-------------------------------- [ * | / ] -----------------------------------

   void LecteurPhraseAvecTable::opMult() {         // <opMult> ::= * | /

	if (    ls.getSymCour()=="*" ||         // si le symbole lu est un '*'
                ls.getSymCour()=="/")           // ou un '/'
		ls.suivant();                   // on passe au suivant
	else                                    // sinon
		erreur("<opMult>");             // on affiche une erreur avec détails
   }
   
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0);                                // plus tard, on levera une exception
}
